/*
   @Copyright:LibreOJ
   @Author:   tjyemail
   @Problem:  https://loj.ac/problem/102
   @Language: C++
   @Datetime: 20-08-19 14:07
   */
// Dinic with Dijkstra , time 354ms

#include <bits/stdc++.h>
using namespace std;

#define VERTEX 405
#define EDGE 15005
// adjacency list
struct Edge {
	int v, cap, price, rev; // cost = cap * price
	Edge(int v=0, int cap=0, int price=0, int rev=0):v(v), cap(cap), price(price), rev(rev){}
	bool operator<(const Edge &e) const { return price>e.price; } // mini-heap
};
vector<Edge> edges[VERTEX];
inline void add(int a, int b, int c, int p) {
	edges[a].push_back(Edge(b, c, p, edges[b].size()));
	edges[b].push_back(Edge(a, 0, -p, edges[a].size()-1));
}
int costs[VERTEX], hd[VERTEX]; // s->k cost, price[s][k]+hd[s]-hd[k]>=0
int curs[VERTEX]; // current available edge position
bool visited[VERTEX];

bool dijkstra(int v, int s, int t) {
	for(int i=0; i++<v; costs[i]=INT_MAX);
	costs[s] = 0;
	int p = 0;
	priority_queue<Edge> que;
	for(que.push(Edge(s)); !que.empty();) {
		s = que.top().v, p = que.top().price;
		que.pop();
		for(int k=0; k<edges[s].size(); ++k) {
			const Edge &ek = edges[s][k];
			if (ek.cap>0 && costs[ek.v]>costs[s]+ek.price+hd[s]-hd[ek.v]) {
				costs[ek.v] = costs[s]+ek.price+hd[s]-hd[ek.v];
				que.push(Edge(ek.v, 0, costs[ek.v]));
			}
		}
	}
	return costs[t]!=INT_MAX; // check if it has path s -> t
}

int dfs(int s, int t, int cap=INT_MAX) {
	if (cap==0 || s==t) return cap;
	int flow = 0, cur = 0;
	visited[s] = true;
	for(int k=curs[s]; k<edges[s].size() && flow!=cap; ++k) {
		curs[s] = k; // record current available edge position
		Edge &ek = edges[s][k];
		// make sure all the arguement paths are Shortest Path
		if (visited[ek.v] || costs[ek.v]!=costs[s]+ek.price+hd[s]-hd[ek.v]) continue;
		cur = dfs(ek.v, t, min(cap-flow, ek.cap));
		if (cur==0) continue;
		ek.cap -= cur;
		edges[ek.v][ek.rev].cap += cur;
		flow += cur;
	}
	visited[s] = false;
	return flow;
}

void minicost(int v, int s, int t) {
	int flow = 0, f = 0, cost = 0;
	while(dijkstra(v, s, t)) { // found shortest path
		// update available capacity flow
		memset(curs, 0, sizeof(int)*(v+1));
		f = dfs(s, t);
		for(int i=0; i++<v; hd[i]+=costs[i]);
		flow += f;
		cost += f*hd[t];
	}
	printf("%d %d\n", flow, cost);
}

int main()
{
	int v, e, a, b, c, p; // vertex, edge
	scanf("%d %d", &v, &e);
	for(int i=0; i++<e; ) {
		scanf("%d %d %d %d", &a, &b, &c, &p); // a->b, capacity, price
		add(a, b, c, p);
	}
	minicost(v, 1, v);
	return 0;
}
